
package com.be.beadmin.design.impl;

import com.be.beadmin.design.dto.input.ProductDrawingInfoDto;
import com.be.beadmin.design.entity.DrawingReview;
import com.be.beadmin.design.entity.DrawingReview_;
import cn.hutool.core.util.ObjectUtil;
import com.be.beadmin.common.entity.PageEntity;
import com.be.beadmin.common.exception.BeadminException;
import com.be.beadmin.common.utils.JpaQueryBuilder;
import com.be.beadmin.common.utils.JpaSortBuilder;
import com.be.beadmin.design.entity.ProductDrawingInfo;
import com.be.beadmin.design.mapper.ProductDrawingInfoMapper;
import com.be.beadmin.design.repository.ProductDrawingInfoRepository;
import com.be.beadmin.design.service.ProductDrawingInfoService;
import com.be.beadmin.project.Util.MinioUtil;
import com.be.beadmin.project.entity.BatchProduct;
import com.be.beadmin.project.entity.Info;
import com.be.beadmin.project.entity.TeamInfo;
import com.be.beadmin.project.repository.BatchProductRepository;
import com.be.beadmin.project.repository.InfoRepository;
import com.be.beadmin.project.repository.TeamInfoRepository;
import com.be.beadmin.service.entity.NotifyInfo;
import com.be.beadmin.service.impl.MinioService;
import com.be.beadmin.service.repository.NotifyInfoRepository;
import com.be.beadmin.service.repository.NotifyTemplateInfoRepository;
import com.be.beadmin.service.service.NotifyTemplateInfoService;
import com.be.beadmin.service.util.DateUtil;
import io.minio.errors.MinioException;
import lombok.RequiredArgsConstructor;
import com.be.beadmin.design.mapper.DrawingReviewMapperEx;
import com.be.beadmin.design.repository.DrawingReviewRepository;
import com.be.beadmin.design.service.DrawingReviewService;
import com.be.beadmin.design.dto.input.DrawingReviewDto;
import com.be.beadmin.design.dto.output.DrawingReviewEx;
import com.be.beadmin.design.dto.input.DrawingReviewQueryCriteria;
import com.be.beadmin.design.mapper.DrawingReviewMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Order;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
* @description 服务实现
* @author zmy
* @date 2023-09-05
**/
@Service
@RequiredArgsConstructor
public class DrawingReviewServiceImpl implements DrawingReviewService {

    @Autowired
    private  DrawingReviewRepository drawingReviewRepository;
    @Autowired
    private  DrawingReviewMapper drawingReviewMapper;
    @Autowired
    private  DrawingReviewMapperEx drawingReviewExMapper;
    @Autowired
    private BatchProductRepository batchProductRepository;
    @Autowired
    private ProductDrawingInfoService productDrawingInfoService;
    @Autowired
    private MinioService minioService;
    @Autowired
    private ProductDrawingInfoRepository productDrawingInfoRepository;

    @Autowired
    private NotifyTemplateInfoService notifyTemplateInfoService;

    @Autowired
    private NotifyTemplateInfoRepository notifyTemplateInfoRepository;

    @Autowired
    private NotifyInfoRepository notifyInfoRepository;

    @Autowired
    private InfoRepository infoRepository;

    @Autowired
    private TeamInfoRepository teamInfoRepository;

    MinioUtil minioUtil = new MinioUtil();
    @Override
    public Page<DrawingReviewEx> getDrawingReviewByPage(PageEntity pageEntity) {
            Pageable pageable = PageRequest.of(
            pageEntity.getCurrent() -1,
            pageEntity.getPageSize());
            Page<DrawingReview> page = drawingReviewRepository.findAll((root, criteriaQuery, criteriaBuilder) -> {
                    List<Predicate> list = new ArrayList<>();
                    Predicate pre1 =   JpaQueryBuilder.getPredicate(root, pageEntity.getFilters(), criteriaBuilder);
                    list.add(pre1);
                    Predicate pre2 = criteriaBuilder.equal(root.get(DrawingReview_.delete), 0); //过滤为0
                    list.add(pre2);
                    Predicate[] p = new Predicate[list.size()];
                    List<Order> orders = new ArrayList<>();
                    if(pageEntity.getSorters() != null && pageEntity.getSorters().size() > 0) {
                        orders = JpaSortBuilder.getPredicate(root, pageEntity.getSorters(), criteriaBuilder);
                        criteriaQuery.orderBy(orders);
                    } else {
                        criteriaQuery.orderBy(criteriaBuilder.desc(root.get(DrawingReview_.createTime).as(Date.class)));
                    }
                    return  criteriaBuilder.and(list.toArray(p));
                    }
                    , pageable);
            Page<DrawingReviewEx> page1 = page.map(drawingReviewExMapper::toEntity);
            return page1;

    }

    @Override
    public void addDrawingReview(DrawingReviewDto drawingReviewDto) {
            DrawingReview result = drawingReviewRepository.findDrawingReviewByIdAndDelete(drawingReviewDto.getId(), 0);
            if(ObjectUtil.isNotEmpty(result)) {
                throw new BeadminException("DrawingReview不存在,请重新查询");
            }
            DrawingReview drawingReview = drawingReviewMapper.toEntity(drawingReviewDto);
            drawingReviewRepository.save(drawingReview);
    }

    @Override
    public void addMutiDrawingReview(List<DrawingReviewDto> drawingReviewDto) throws ParseException {
        List<String> drawingIds = drawingReviewDto.stream().map(DrawingReviewDto::getDrawingId).collect(Collectors.toList());
        List<ProductDrawingInfo> drawingInfos= productDrawingInfoRepository.findAllById(drawingIds);
        List<BatchProduct> products = new ArrayList<>();

        //生成审批流
        List<DrawingReviewDto> reviewList = drawingInfos.stream().map(item -> {
            DrawingReviewDto review = new DrawingReviewDto();
            BeanUtils.copyProperties(item, review, "id");

            BatchProduct product = batchProductRepository.findBatchProductByProductCodeAndDelete(item.getProductCode(), 0);
            products.add(product);

            review.setProjectName(product.getProjectName());
//            review.setDelete(0);
            review.setDrawingId(item.getId());
            return review;
        }).collect(Collectors.toList());
        drawingReviewRepository.saveAll(drawingReviewMapper.toEntity(reviewList));

        // 消息通知 :工程师-> 技术经理
        //-----------------------------------------------------------------------
        // 申请人 发送 工时补录 待办  审批人
        for (BatchProduct product : products) {
            NotifyInfo notifyInfo = new NotifyInfo();
            notifyInfo.setModuleName("设计管理");
            notifyInfo.setFuncName("技术文件变更");
            notifyInfo.setNotifyDesc("非标柜体编码为[" + product.getProductCode() + "]--新增图纸,待审批");
            notifyInfo.setNotifyType("待办");

            if (product.getEngineer() == null) {
                notifyInfo.setSenderName("-");
            } else {
                notifyInfo.setSenderName(product.getEngineer());
            }

            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH-mm");
            Date date = new Date();
            notifyInfo.setSendTime(df.parse(df.format(date)));

            // ?1没有 用户id字段，用的用户名
            notifyInfo = notifyInfoRepository.save(notifyInfo);

            Info info = infoRepository.findInfoByIdAndDelete(product.getInfoId(), 0);
            TeamInfo teaminfo = teamInfoRepository.findTeamInfoByTeamIdAndCategoryAndDelete(info.getTeamId(), "技术经理", 0);
            if (teaminfo.getUserName() != null) {
                notifyTemplateInfoService.sendNotify(notifyInfo, -2, teaminfo.getUserName(), teaminfo.getUserId());
            }
        }

    }

    @Override
    public void updateDrawingReview(DrawingReviewDto drawingReviewDto) {
            DrawingReview drawingReview = drawingReviewRepository.findDrawingReviewById(drawingReviewDto.getId());
            drawingReview = drawingReviewMapper.toEntity(drawingReviewDto);
            drawingReviewRepository.save(drawingReview);
    }


    @Override
    public void delDrawingReview(String id) {
        DrawingReview drawingReview = drawingReviewRepository.findDrawingReviewById(id);
        drawingReview.setDelete(1);
        drawingReviewRepository.save(drawingReview);
    }

    @Override
    public void delDrawingReviews (List<String> ids) { }

    //图纸变更审核
    @Transactional
    public void confirmDrawingReview(String id, int reviewState,String reviewMemo, String version) throws Exception {

        //  Done
        //  1. 审核结果+备注+版本
        //  2. 通过后：立即生效, 更新状态, 更新白底；未通过: 如果是电气原理图/箱柜接线表, 则将其已上传标识为0, 删除图纸信息 ProductDrawingInfo

        DrawingReview drawingReview = drawingReviewRepository.findDrawingReviewByIdAndDelete(id, 0);
        drawingReview.setChangeStatus(reviewState);
        drawingReview.setVersion(version);
        drawingReview.setMemo(reviewMemo);
        drawingReviewRepository.save(drawingReview);

        BatchProduct product = batchProductRepository.findBatchProductByProductCodeAndDelete(drawingReview.getProductCode(),0);

        if(reviewState==2){
            List<ProductDrawingInfo> productDrawingInfos =  productDrawingInfoRepository.findProductDrawingInfosByProductCodeAndCategoryAndDrawingNameAndDelete(drawingReview.getProductCode(), drawingReview.getCategory(), drawingReview.getDrawingName(), 0);
            // 将其他同类型、同名称的文件失效
            for (ProductDrawingInfo p: productDrawingInfos) {
                p.setIsActive(0);
            }
            productDrawingInfoRepository.saveAll(productDrawingInfos);

            // 改变DrawingInfo状态
            ProductDrawingInfo productDrawingInfo = productDrawingInfoRepository.findProductDrawingInfoByIdAndDelete(drawingReview.getDrawingId(), 0);
            productDrawingInfo.setDelete(0);
            productDrawingInfo.setIsActive(1);
            productDrawingInfo.setChangeOrAdd("0");
            productDrawingInfo.setChangeStatus(reviewState);
            productDrawingInfo.setVersion(version);
            productDrawingInfoRepository.save(productDrawingInfo);

            // 改变batchProduct中图纸信息
            product.setDrawingTime(DateUtil.transDateFormat(new Date()));
            product.setDrawingIsChange(1);
            product.setDrawingId(productDrawingInfo.getId());
            batchProductRepository.save(product);

            // -------------消息通知------------
            // 审批通过后进行消息通知：技术经理->生产与分料组
            List<String> cateGoryList = Arrays.asList("生产人员", "生产组长", "生产经理","分料人员","分料组长","分料经理");

            NotifyInfo notifyInfo =new NotifyInfo();
            notifyInfo.setModuleName("设计管理");
            notifyInfo.setFuncName("技术文件变更");
            notifyInfo.setNotifyDesc("非标柜体编码为["+product.getProductCode()+"]--技术文件变更审批通过");
            notifyInfo.setNotifyType("通知");

            Info projectInfo = infoRepository.findInfoByIdAndDelete(product.getInfoId(), 0);
            TeamInfo teaminfo = teamInfoRepository.findTeamInfoByTeamIdAndCategoryAndDelete(projectInfo.getTeamId(), "技术经理", 0);
            if (teaminfo.getUserName()==null){
                notifyInfo.setSenderName("-");
            }else{
                notifyInfo.setSenderName(teaminfo.getUserName());
                notifyInfo.setSenderId(teaminfo.getUserId());
            }
            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH-mm");
            Date date = new Date();
            notifyInfo.setSendTime(df.parse(df.format(date)));
            notifyInfo = notifyInfoRepository.save(notifyInfo);

            List<TeamInfo> teamList = teamInfoRepository.findTeamInfoByTeamIdAndCategoryInAndDelete(projectInfo.getTeamId(), cateGoryList, 0);
            Set<TeamInfo> sets = new HashSet<>(teamList);       // 防止对不同角色相同的人重复发送
            for (TeamInfo item: sets){
                notifyTemplateInfoService.sendNotify(notifyInfo,-1,item.getUserName(),item.getUserId());
            }

        } else if (reviewState == 3) {

            // 改变batchProduct中图纸信息
//            if (drawingReview.getCategory().equals("电气原理图")){
//                product.setIsElectDrawingUploaded(product.getIsElectDrawingUploaded()-1);
//            }
//            if (drawingReview.getCategory().equals("箱柜接线表")){
//                product.setIsWireFileUploaded(product.getIsWireFileUploaded()-1);
//            }

            // 驳回逻辑：改变状态 图纸保留
            ProductDrawingInfo drawingInfo = productDrawingInfoRepository.findProductDrawingInfoById(drawingReview.getDrawingId());
//            drawingInfo.setDelete(1);
            drawingInfo.setChangeStatus(reviewState);
            productDrawingInfoRepository.save(drawingInfo);

            // 消息通知： 驳回后技术经理->工程师
            // ---------------------------------------------

            NotifyInfo notifyInfo = new NotifyInfo();
            notifyInfo.setModuleName("设计管理");
            notifyInfo.setFuncName("技术文件变更");
            notifyInfo.setNotifyDesc("非柜体编码为["+product.getProductCode()+"]--技术文件变更审批被驳回");
            notifyInfo.setNotifyType("通知");

            Info info = infoRepository.findInfoByIdAndDelete(product.getInfoId(),0);
            TeamInfo teaminfo = teamInfoRepository.findTeamInfoByTeamIdAndCategoryAndDelete(info.getTeamId(), "技术经理", 0);

            if (teaminfo.getUserName()==null){
                notifyInfo.setSenderName("-");
            }else{
                notifyInfo.setSenderName(teaminfo.getUserName());
                notifyInfo.setSenderId(teaminfo.getUserId());
            }
            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH-mm");
            Date date = new Date();
            notifyInfo.setSendTime(df.parse(df.format(date)));
            notifyInfo = notifyInfoRepository.save(notifyInfo);

            if (product.getEngineer() != null) {
                notifyTemplateInfoService.sendNotify(notifyInfo,-1,product.getEngineer(),null);
            }
        }
    }

    @Override
    public int countUnreviewedDrawing() {
        return drawingReviewRepository.countDrawingReviewByChangeStatusAndDelete(0,0);
    }
}